package com.accedo.achievements.dataaccess.dao.impl;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.accedo.achievements.dataaccess.dao.AppDao;
import com.accedo.achievements.dataaccess.model.App;

/**
 * A DAO class with application model database operations 
 * @author Bo Liang
 */
@Component
public class AppDaoImpl implements AppDao{

	private static final Logger log = LoggerFactory.getLogger(AppDaoImpl.class);
	
	private SessionFactory sessionFactory; //injection
	private App app; //injection
	
	// Constructor
	AppDaoImpl() {}; 
	
	/**
	 * Get user's application serial number List by using user id.
	 * <p>by using user id, this function returns the application serial number 
	 * which applications that user has already downloaded or bought, 
	 * system will create a connection in the many-to-many table about user and application's achievements,
	 * this function could return the application sn based on the achievements.
	 * @param user_id	user id
	 * @return			List of application serial number
	 */
	@SuppressWarnings("unchecked")
	public List<String> getAppsnListByUseid(int user_id) {
		log.debug("Entering getAppsnListByUseid(user_id = {})", user_id);
		
		List<String> appsnList = new ArrayList<String>(); 
		Session session = null; 
		try {
			session = sessionFactory.openSession();
			Query query = session.createSQLQuery("select distinct app_sn from t_user_achievement where user_id = :user_id order by app_sn desc")
					.setParameter("user_id", user_id); 
			appsnList = query.list(); 
		} catch (Exception e) {
			e.printStackTrace();
			log.error("getAppsnListByUseid Catch Exception: {}", e.getMessage());
		} finally {
			session.close();
		}
		
		log.debug("Leaving getAppsnListByUseid() : appsnList.size = {})", appsnList.size());
		return appsnList; 
	}
	
	/**
	 * Get application object by achievement sn.
	 * <p>obtain the application object instance by using this application serial number<br>
	 * @param app_sn	application serial number
	 * @return			application object
	 */
	public App getAppByAppsn(String app_sn) {
		log.debug("Entering getAppByAppsn(app_sn = {})", app_sn);
		
		Session session = null; 
		try {
//			session = SessionFactoryUtil.getSessionFactory().openSession(); 
			session = sessionFactory.openSession();
			Query query = session.createQuery("from App app where app.app_sn = :app_sn")
						  .setParameter("app_sn", app_sn); 
			app = (App)query.uniqueResult();  
		} catch (Exception e) {
			e.printStackTrace();
			log.error("getAppByAppsn Catch Exception: {}", e.getMessage());
		} finally {
//			SessionFactoryUtil.closeSession(session);
			session.close();
		}
		
		log.debug("Leaving getAppByAppsn() : app.name = {})", app.getApp_name());
		return app; 
	}
	
	/**
	 * Get all applications from database.
	 * @return application objects List
	 */
	@SuppressWarnings("unchecked")
	public List<App> getAppList() {
		log.debug("Entering getAppList()");
		
		List<App> appList = new ArrayList<App>(); 
		Session session = null; 
		try {
//			session = SessionFactoryUtil.getSessionFactory().openSession(); 
			session = sessionFactory.openSession();
			Query query = session.createQuery("from App app"); 
			appList = query.list();  
		} catch (Exception e) {
			e.printStackTrace();
			log.error("getAppList Catch Exception: {}", e.getMessage());
		} finally {
//			SessionFactoryUtil.closeSession(session);
			session.close();
		}
		
		log.debug("Leaving getAppList() : appList.size = {}", appList.size());
		return appList;
	}
	
	
	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	
	@Resource
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	public App getApp() {
		return app;
	}
	
	@Resource
	public void setApp(App app) {
		this.app = app;
	}
	
}
